#pragma once

#include "ast.h"
#include "parser.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/DenseMap.h"

// 通过访问者模式生成代码
class CodeGen : public Visitor
{
public:
    CodeGen(std::shared_ptr<Program> program)
    {
        module = std::make_shared<llvm::Module>("expr", context);
        VisitProgram(program.get());
    }

public:
    llvm::Value *VisitProgram(Program *p) override;
    llvm::Value *VisitDeclStmt(DeclStmt *decl) override;
    llvm::Value *VisitBlockStmt(BlockStmt *block) override;
    llvm::Value *VisitIfStmt(IfStmt *ifStmt) override;
    llvm::Value *VisitForStmt(ForStmt *forStmt) override;
    llvm::Value *VisitBreakStmt(BreakStmt *breakStmt) override;
    llvm::Value *VisitContinueStmt(ContinueStmt *continueStmt) override;
    llvm::Value *VisitVariableDecl(VariableDecl *decl) override;
    llvm::Value *VisitVariableAccessExpr(VariableAccessExpr *varaccExpr) override;
    llvm::Value *VisitAssignExpr(AssignExpr *assignExpr) override;
    llvm::Value *VisitBinaryExpr(BinaryExpr *binaryExpr) override;
    llvm::Value *VisitNumberExpr(NumberExpr *factorExpr) override;

private:
    llvm::LLVMContext context;
    llvm::IRBuilder<> irBuilder{context};
    std::shared_ptr<llvm::Module> module;
    llvm::Function *curFunc{nullptr};
    llvm::StringMap<std::pair<llvm::Value *, llvm::Type *>> varAddrTyMap;
    llvm::DenseMap<ASTNode *, llvm::BasicBlock *> breakBBs;
    llvm::DenseMap<ASTNode *, llvm::BasicBlock *> continueBBs;
};